import type { SearchPageTitleCleanupConfig, SearchSelectorConfig } from '../index'
import type {
  PageSearchMetaSourceConfig,
  PageSearchMetaTimeConfig,
} from './index'
import { StyleModule } from '../../../../../../lib/abstract'
import { PageHandler } from '../../../../../../lib/page_handler'
import { BingPageType } from '../../../../../../lib/page_handler/platform/bing/types'
import { ToolKit } from '../../../../../../lib/utils/toolkit'
import {
  HOSTNAME,
  logger,
  SUPPORTED_PLATFORMS,
} from '../../../../../../types/constants'
import { SearchStyle } from './index'

export class BingStyle extends StyleModule {
  readonly name: string = 'BingStyle'
  private static instance: BingStyle
  private pageHandler: PageHandler = PageHandler.getInstance()
  private searchStyle: SearchStyle = SearchStyle.getInstance()
  private readonly pageType = this.pageHandler.pages.bing.pageType
  private readonly selectors: SearchSelectorConfig = this.pageHandler.pages.bing.getResultSelectors()
  private webObserver: MutationObserver | null = null
  private videoObserver: MutationObserver | null = null
  private dictionaryObserver: MutationObserver | null = null

  constructor() {
    super()

    if (HOSTNAME !== SUPPORTED_PLATFORMS.BING)
      return

    this.init()
  }

  static getInstance(): BingStyle {
    if (!BingStyle.instance) {
      BingStyle.instance = new BingStyle()
    }
    return BingStyle.instance
  }

  /**
   * 初始化
   */
  init(): void {
    this.initWebObserver()
    this.initVideoObserver()
    this.initDictionaryObserver()
    this.updateSearchStyle()
    this.initResultMeta()
    this.updateTitle()
  }

  /**
   * 初始化网页观察器
   */
  private initWebObserver() {
    if (this.pageType !== BingPageType.Web)
      return

    // 如果已经存在观察器，先断开
    this.stopObservation()

    // 遮罩观察器
    this.webObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
          if (Array.from(mutation.addedNodes).some(n => (n as Element).id === 'b_content')) {
            // 由于是同步添加节点，所以网页内容是完全加载的
            logger.attention(`[${this.name}] 网页触发更新`)
            this.handleWebUpdate()
          }
        }
      })
    })

    // 监听变化
    this.webObserver.observe(document.body, {
      childList: true, // 只需要直接子元素变化
      subtree: false,
    })
  }

  /**
   * 初始化视频观察器
   */
  private initVideoObserver() {
    if (this.pageType !== BingPageType.Video)
      return

    // 如果已经存在观察器，先断开
    this.stopObservation()

    // 遮罩观察器
    this.videoObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
          if (Array.from(mutation.addedNodes).some(n => ToolKit.ui.element.isElementWithClasses(n, ['vsb_canvas', 'isvsr']))) {
            // 由于是同步添加节点，所以更多视频内容是完全加载的
            logger.attention(`[${this.name}] 更多视频已加载`)
            this.handleMoreVideoAdded()
          }
        }
      })
    })

    const selector = '#b_content #vm_res #vm_c'
    const target = document.querySelector(selector)

    if (!target) {
      logger.warn(`[${this.name}] 视频结果列表容器未找到`, selector)
      return
    }

    // 监听变化
    this.videoObserver.observe(target, {
      childList: true, // 只需要直接子元素变化
      subtree: false,
    })
  }

  /**
   * 初始化字典观察器
   */
  private initDictionaryObserver() {
    if (this.pageType !== BingPageType.Dictionary)
      return

    // 如果已经存在观察器，先断开
    this.stopObservation()

    // 记录上一次的 display 值
    let lastDisplayValue: string | null = null

    // 遮罩观察器
    this.dictionaryObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
          const target = mutation.target as HTMLElement
          const currentDisplay = target.style.display

          // 检测从 "XXX" 变为 "none" 的情况
          if (lastDisplayValue !== 'none' && currentDisplay === 'none') {
            logger.attention(`[${this.name}] 字典结果触发更新`)
            this.handleDictionaryUpdate()
          }

          // 更新最后一次记录的值
          lastDisplayValue = currentDisplay
        }
      })
    })

    const selector = '#loaddataid'
    const target = document.querySelector(selector)

    if (!target) {
      logger.warn(`[${this.name}] 字典结果加载容器未找到`, selector)
      return
    }

    // 初始化记录当前 display 值
    lastDisplayValue = (target as HTMLElement).style.display

    // 监听变化
    this.dictionaryObserver.observe(target, {
      childList: false,
      subtree: false,
      attributes: true,
      attributeFilter: ['style'], // 只监听 style 属性
    })
  }

  /**
   * 处理网页更新
   */
  handleWebUpdate(): void {
    this.updateSearchStyle()
    this.initResultMeta()
    this.updateTitle()
  }

  /**
   * 处理更多视频添加
   */
  handleMoreVideoAdded(): void {
    this.updateSearchStyle()
    this.initResultMeta()
    this.updateTitle()
  }

  /**
   * 处理字典加载完成
   */
  handleDictionaryUpdate(): void {
    this.updateSearchStyle()
    this.initResultMeta()
    this.updateTitle()
  }

  /**
   * 停止观察
   */
  stopObservation(): void {
    switch (this.pageType) {
      case BingPageType.Web:
        this.webObserver?.disconnect()
        this.webObserver = null
        break
      case BingPageType.Video:
        this.videoObserver?.disconnect()
        this.videoObserver = null
        break
      case BingPageType.Dictionary:
        this.dictionaryObserver?.disconnect()
        this.dictionaryObserver = null
        break
    }
  }

  /**
   * 初始化搜索样式
   */
  updateSearchStyle(forceUpdate?: boolean): void {
    const supportPages = [
      BingPageType.Web,
      BingPageType.Video,
      BingPageType.Academic,
      BingPageType.Dictionary,
    ]

    this.searchStyle.setBaseStyle(this.selectors, { supportPages, forceUpdate })
  }

  /**
   * 初始化结果元数据
   */
  initResultMeta(): void {
    const sourceConfig: PageSearchMetaSourceConfig = {
      [BingPageType.Video]: {
        base: {
          selector: '.mc_vtvc_meta_row .mc_vtvc_meta_row_channel',
          iconSelector: '.mc_vtvc_meta_row:not(:has(.meta_pd_content)) span:first-child',
          container: '.mc_vtvc_meta_row',
          enableIcon: true,
        },
      },
      [BingPageType.Academic]: {
        base: {
          selector: '.caption_display_url cite',
          container: '.caption_display_url',
        },
      },
      [BingPageType.Dictionary]: {
        base: {
          selector: '.sen_li.b_regtxt a',
          container: '.sen_li.b_regtxt',
        },
      },
    }

    const timeConfig: PageSearchMetaTimeConfig = {
      [BingPageType.Web]: {
        selector: '.b_caption p, .b_imgcap_main p',
        cleanFunc: (text: string) => text.includes('·') ? text.split('·')[0] : '',
        deleteFunc: (html: string) => html.replace(/^[\s\S]*?·/, '').trim(),
        hideSource: false,
      },
      [BingPageType.Video]: {
        selector: '.mc_vtvc_meta_row .meta_pd_content',
      },
    }

    this.searchStyle.createResultMeta(
      this.selectors.selector,
      {
        leftConfig: sourceConfig,
        rightConfig: timeConfig,
      },
    )
  }

  /**
   * 更新标题
   */
  updateTitle(): void {
    const supportPages = [
      BingPageType.Web,
      BingPageType.Video,
    ]

    if (!supportPages.includes(this.pageType as BingPageType))
      return

    const config: SearchPageTitleCleanupConfig = {}

    this.searchStyle.updateTitle({
      config,
      container: this.selectors.selector,
      titleSelector: '.mc_vtvc_title strong',
      highlightKeywords: ToolKit.browser.url.getUrlParams('q'),
    })
  }
}
